

<!DOCTYPE html>
<html lang="zh-CN" data-default-color-scheme=auto>



<head>
  <meta charset="UTF-8">
  <link rel="apple-touch-icon" sizes="76x76" href="/img/egg.png">
  <link rel="icon" href="/img/egg.png">
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=5.0, shrink-to-fit=no">
  <meta http-equiv="x-ua-compatible" content="ie=edge">
  
  <meta name="theme-color" content="#2f4154">
  <meta name="author" content="十一的蛋炒饭">
  <meta name="keywords" content="">
  
    <meta name="description" content="Web开发笔记2 后端 SpringBoot  1、SpringSpring 官网 1Spring框架是一个开放源代码的JavaEE应用程序框架，由Rod Johnson发起，是针对bean的生命周期进行管理的轻量级容器（lightweight container）。  为什么要学习 Spring 1Spring使Java编程对每个人来说都更快、更容易、更安全。Spring对速度、简单性和生产力的">
<meta property="og:type" content="article">
<meta property="og:title" content="Web 开发笔记2 | 后端 Spring Boot、HTTP协议、Web服务器、Tomcat">
<meta property="og:url" content="http://example.com/2024/03/11/Web%E5%BC%80%E5%8F%91%E7%AC%94%E8%AE%B02-%E5%90%8E%E7%AB%AF-Spring-Boot%E3%80%81HTTP%E5%8D%8F%E8%AE%AE%E3%80%81Web%E6%9C%8D%E5%8A%A1%E5%99%A8%E3%80%81Tomcat/index.html">
<meta property="og:site_name" content="十一的蛋炒饭的博客">
<meta property="og:description" content="Web开发笔记2 后端 SpringBoot  1、SpringSpring 官网 1Spring框架是一个开放源代码的JavaEE应用程序框架，由Rod Johnson发起，是针对bean的生命周期进行管理的轻量级容器（lightweight container）。  为什么要学习 Spring 1Spring使Java编程对每个人来说都更快、更容易、更安全。Spring对速度、简单性和生产力的">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://uni-pic-bed.oss-cn-hangzhou.aliyuncs.com/blog2024/202403110308926.png">
<meta property="og:image" content="https://uni-pic-bed.oss-cn-hangzhou.aliyuncs.com/blog2024/202403110311565.png">
<meta property="og:image" content="https://uni-pic-bed.oss-cn-hangzhou.aliyuncs.com/blog2024/202403110315686.png">
<meta property="og:image" content="https://uni-pic-bed.oss-cn-hangzhou.aliyuncs.com/blog2024/202403110330865.png">
<meta property="og:image" content="https://uni-pic-bed.oss-cn-hangzhou.aliyuncs.com/blog2024/202403110332470.png">
<meta property="og:image" content="https://uni-pic-bed.oss-cn-hangzhou.aliyuncs.com/blog2024/202403110333463.png">
<meta property="og:image" content="https://uni-pic-bed.oss-cn-hangzhou.aliyuncs.com/blog2024/202403110349732.png">
<meta property="og:image" content="https://uni-pic-bed.oss-cn-hangzhou.aliyuncs.com/blog2024/202403110357194.png">
<meta property="og:image" content="https://uni-pic-bed.oss-cn-hangzhou.aliyuncs.com/blog2024/202403110406639.png">
<meta property="og:image" content="https://uni-pic-bed.oss-cn-hangzhou.aliyuncs.com/blog2024/202403110419104.png">
<meta property="og:image" content="https://uni-pic-bed.oss-cn-hangzhou.aliyuncs.com/blog2024/202403110951214.png">
<meta property="og:image" content="https://uni-pic-bed.oss-cn-hangzhou.aliyuncs.com/blog2024/202403110949742.png">
<meta property="og:image" content="https://uni-pic-bed.oss-cn-hangzhou.aliyuncs.com/blog2024/202403111017937.png">
<meta property="og:image" content="https://uni-pic-bed.oss-cn-hangzhou.aliyuncs.com/blog2024/202403111757052.png">
<meta property="og:image" content="https://uni-pic-bed.oss-cn-hangzhou.aliyuncs.com/blog2024/202403111818177.png">
<meta property="article:published_time" content="2024-03-11T11:08:00.000Z">
<meta property="article:modified_time" content="2024-03-13T04:11:40.078Z">
<meta property="article:author" content="十一的蛋炒饭">
<meta property="article:tag" content="Web">
<meta property="article:tag" content="SpringBoot">
<meta property="article:tag" content="HTTP">
<meta property="article:tag" content="Tomcat">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:image" content="https://uni-pic-bed.oss-cn-hangzhou.aliyuncs.com/blog2024/202403110308926.png">
  
  
  
  <title>Web 开发笔记2 | 后端 Spring Boot、HTTP协议、Web服务器、Tomcat - 十一的蛋炒饭的博客</title>

  <link  rel="stylesheet" href="https://lib.baomitu.com/twitter-bootstrap/4.6.1/css/bootstrap.min.css" />



  <link  rel="stylesheet" href="https://lib.baomitu.com/github-markdown-css/4.0.0/github-markdown.min.css" />

  <link  rel="stylesheet" href="https://lib.baomitu.com/hint.css/2.7.0/hint.min.css" />

  <link  rel="stylesheet" href="https://lib.baomitu.com/fancybox/3.5.7/jquery.fancybox.min.css" />



<!-- 主题依赖的图标库，不要自行修改 -->
<!-- Do not modify the link that theme dependent icons -->

<link rel="stylesheet" href="//at.alicdn.com/t/font_1749284_hj8rtnfg7um.css">



<link rel="stylesheet" href="//at.alicdn.com/t/font_1736178_lbnruvf0jn.css">


<link  rel="stylesheet" href="/css/main.css" />


  <link id="highlight-css" rel="stylesheet" href="/css/highlight.css" />
  
    <link id="highlight-css-dark" rel="stylesheet" href="/css/highlight-dark.css" />
  




  <script id="fluid-configs">
    var Fluid = window.Fluid || {};
    Fluid.ctx = Object.assign({}, Fluid.ctx)
    var CONFIG = {"hostname":"example.com","root":"/","version":"1.9.7","typing":{"enable":true,"typeSpeed":60,"cursorChar":"","loop":false,"scope":["home"]},"anchorjs":{"enable":true,"element":"h1,h2,h3,h4,h5,h6","placement":"left","visible":"hover","icon":"§"},"progressbar":{"enable":true,"height_px":3,"color":"#29d","options":{"showSpinner":false,"trickleSpeed":100}},"code_language":{"enable":true,"default":"TEXT"},"copy_btn":true,"image_caption":{"enable":true},"image_zoom":{"enable":true,"img_url_replace":["",""]},"toc":{"enable":true,"placement":"right","headingSelector":"h1,h2,h3,h4,h5,h6","collapseDepth":0},"lazyload":{"enable":true,"loading_img":"/img/loading.gif","onlypost":false,"offset_factor":2},"web_analytics":{"enable":false,"follow_dnt":true,"baidu":null,"google":{"measurement_id":null},"tencent":{"sid":null,"cid":null},"woyaola":null,"cnzz":null,"leancloud":{"app_id":null,"app_key":null,"server_url":null,"path":"window.location.pathname","ignore_local":false}},"search_path":"/local-search.xml","include_content_in_search":true};

    if (CONFIG.web_analytics.follow_dnt) {
      var dntVal = navigator.doNotTrack || window.doNotTrack || navigator.msDoNotTrack;
      Fluid.ctx.dnt = dntVal && (dntVal.startsWith('1') || dntVal.startsWith('yes') || dntVal.startsWith('on'));
    }
  </script>
  <script  src="/js/utils.js" ></script>
  <script  src="/js/color-schema.js" ></script>
  


  
<meta name="generator" content="Hexo 7.1.1"></head>


<body>
  

  <header>
    

<div class="header-inner" style="height: 70vh;">
  <nav id="navbar" class="navbar fixed-top  navbar-expand-lg navbar-dark scrolling-navbar">
  <div class="container">
    <a class="navbar-brand" href="/">
      <strong>十一的蛋炒饭 的博客</strong>
    </a>

    <button id="navbar-toggler-btn" class="navbar-toggler" type="button" data-toggle="collapse"
            data-target="#navbarSupportedContent"
            aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
      <div class="animated-icon"><span></span><span></span><span></span></div>
    </button>

    <!-- Collapsible content -->
    <div class="collapse navbar-collapse" id="navbarSupportedContent">
      <ul class="navbar-nav ml-auto text-center">
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/" target="_self">
                <i class="iconfont icon-home-fill"></i>
                <span>首页</span>
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/archives/" target="_self">
                <i class="iconfont icon-archive-fill"></i>
                <span>归档</span>
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/categories/" target="_self">
                <i class="iconfont icon-category-fill"></i>
                <span>分类</span>
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/tags/" target="_self">
                <i class="iconfont icon-tags-fill"></i>
                <span>标签</span>
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/about/" target="_self">
                <i class="iconfont icon-user-fill"></i>
                <span>关于</span>
              </a>
            </li>
          
        
        
          <li class="nav-item" id="search-btn">
            <a class="nav-link" target="_self" href="javascript:;" data-toggle="modal" data-target="#modalSearch" aria-label="Search">
              <i class="iconfont icon-search"></i>
            </a>
          </li>
          
        
        
          <li class="nav-item" id="color-toggle-btn">
            <a class="nav-link" target="_self" href="javascript:;" aria-label="Color Toggle">
              <i class="iconfont icon-dark" id="color-toggle-icon"></i>
            </a>
          </li>
        
      </ul>
    </div>
  </div>
</nav>

  

<div id="banner" class="banner" parallax=true
     style="background: url('/img/win7.jpg') no-repeat center center; background-size: cover;">
  <div class="full-bg-img">
    <div class="mask flex-center" style="background-color: rgba(0, 0, 0, 0.3)">
      <div class="banner-text text-center fade-in-up">
        <div class="h2">
          
            <span id="subtitle">Web 开发笔记2 | 后端 Spring Boot、HTTP协议、Web服务器、Tomcat</span>
          
        </div>

        
          
  <div class="mt-3">
    
    
      <span class="post-meta">
        <i class="iconfont icon-date-fill" aria-hidden="true"></i>
        <time datetime="2024-03-11 19:08" pubdate>
          2024年3月11日 晚上
        </time>
      </span>
    
  </div>

  <div class="mt-1">
    
      <span class="post-meta mr-2">
        <i class="iconfont icon-chart"></i>
        
          3.3k 字
        
      </span>
    

    
      <span class="post-meta mr-2">
        <i class="iconfont icon-clock-fill"></i>
        
        
        
          28 分钟
        
      </span>
    

    
    
  </div>


        
      </div>

      
    </div>
  </div>
</div>

</div>

  </header>

  <main>
    
      

<div class="container-fluid nopadding-x">
  <div class="row nomargin-x">
    <div class="side-col d-none d-lg-block col-lg-2">
      
  <aside class="sidebar category-bar" style="margin-right: -1rem">
    





<div class="category-list">
  
  
    
    
    
    <div class="category row nomargin-x">
      <a class="category-item 
          list-group-item category-item-action col-10 col-md-11 col-xm-11" title="Web开发"
        id="heading-3b451acfb78b69289662a6dd4d9d042c" role="tab" data-toggle="collapse" href="#collapse-3b451acfb78b69289662a6dd4d9d042c"
        aria-expanded="true"
      >
        Web开发
        <span class="list-group-count">(3)</span>
        <i class="iconfont icon-arrowright"></i>
      </a>
      
      <div class="category-collapse collapse show" id="collapse-3b451acfb78b69289662a6dd4d9d042c"
           role="tabpanel" aria-labelledby="heading-3b451acfb78b69289662a6dd4d9d042c">
        
        
          
  <div class="category-post-list">
    
    
      
      
        <a href="/2024/03/06/Web-%E5%BC%80%E5%8F%91%E7%AC%94%E8%AE%B01-%E5%89%8D%E5%90%8E%E7%AB%AF%E5%88%86%E7%A6%BB%E5%BC%80%E5%8F%91%E3%80%81Vue2%E9%A1%B9%E7%9B%AE%E5%BC%80%E5%8F%91/" title="Web 开发笔记1 | 前后端分离开发、Vue2项目开发"
           class="list-group-item list-group-item-action
           ">
          <span class="category-post">Web 开发笔记1 | 前后端分离开发、Vue2项目开发</span>
        </a>
      
    
      
      
        <a href="/2024/03/11/Web%E5%BC%80%E5%8F%91%E7%AC%94%E8%AE%B02-%E5%90%8E%E7%AB%AF-Spring-Boot%E3%80%81HTTP%E5%8D%8F%E8%AE%AE%E3%80%81Web%E6%9C%8D%E5%8A%A1%E5%99%A8%E3%80%81Tomcat/" title="Web 开发笔记2 | 后端 Spring Boot、HTTP协议、Web服务器、Tomcat"
           class="list-group-item list-group-item-action
           active">
          <span class="category-post">Web 开发笔记2 | 后端 Spring Boot、HTTP协议、Web服务器、Tomcat</span>
        </a>
      
    
      
      
        <a href="/2024/03/12/Web-%E5%BC%80%E5%8F%91%E7%AC%94%E8%AE%B03-Postman-%E3%80%81SpringBoot-%E8%8E%B7%E5%8F%96%E4%B8%8D%E5%90%8C%E7%9A%84%E8%AF%B7%E6%B1%82%E5%8F%82%E6%95%B0%E3%80%81Spring-Boot-%E5%93%8D%E5%BA%94%E6%95%B0%E6%8D%AE%E3%80%81Spring-%E7%9A%84-IOC%E6%8E%A7%E5%88%B6%E5%8F%8D%E8%BD%AC%E5%92%8CDI-%E4%BE%9D%E8%B5%96%E6%B3%A8%E5%85%A5%E3%80%81%E9%A1%B9%E7%9B%AE%E5%88%86%E5%B1%82%E8%A7%A3%E8%80%A6%E7%9A%84%E5%AE%9E%E7%8E%B0%E3%80%81Bean-%E6%B3%A8%E5%85%A5%E7%9A%84%E6%B3%A8%E8%A7%A3/" title="Web 开发笔记3 | Postman 、SpringBoot 获取不同的请求参数、Spring Boot 响应数据、Spring 的 IOC控制反转和DI 依赖注入、项目分层解耦的实现、Bean 注入的注解"
           class="list-group-item list-group-item-action
           ">
          <span class="category-post">Web 开发笔记3 | Postman 、SpringBoot 获取不同的请求参数、Spring Boot 响应数据、Spring 的 IOC控制反转和DI 依赖注入、项目分层解耦的实现、Bean 注入的注解</span>
        </a>
      
    
  </div>

        
      </div>
    </div>
  
</div>


  </aside>


    </div>

    <div class="col-lg-8 nopadding-x-md">
      <div class="container nopadding-x-md" id="board-ctn">
        <div id="board">
          <article class="post-content mx-auto">
            <h1 id="seo-header">Web 开发笔记2 | 后端 Spring Boot、HTTP协议、Web服务器、Tomcat</h1>
            
              <p id="updated-time" class="note note-info" style="display: none">
                
                  
                    本文最后更新于 2024-03-13T12:11:40+08:00
                  
                  

                
              </p>
            
            
              <div class="markdown-body">
                
                <p>Web开发笔记2 后端 SpringBoot </p>
<h2 id="1、Spring"><a href="#1、Spring" class="headerlink" title="1、Spring"></a>1、Spring</h2><p><a target="_blank" rel="noopener" href="https://spring.io/">Spring 官网</a></p>
<figure class="highlight mipsasm"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs mipsasm">Spring框架是一个开放源代码的<span class="hljs-keyword">JavaEE应用程序框架，由Rod </span><span class="hljs-keyword">Johnson发起，是针对bean的生命周期进行管理的轻量级容器（lightweight </span>container）。<br></code></pre></td></tr></table></figure>

<p><a target="_blank" rel="noopener" href="https://spring.io/why-spring">为什么要学习 Spring</a></p>
<figure class="highlight"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs">Spring使Java编程对每个人来说都更快、更容易、更安全。Spring对速度、简单性和生产力的关注使其成为世界上最流行的Java框架。<br></code></pre></td></tr></table></figure>

<p>截止 2024年3月11日，<a target="_blank" rel="noopener" href="https://spring.io/projects">Spring 全家桶</a> 共有24个部分，分别是：</p>
<ol>
<li><strong>Spring Framework</strong>：为依赖项注入、事务管理、Web应用、数据访问、消息传递等提供核心支持。</li>
<li><strong>Spring Boot</strong>：以固定的方式构建 Spring 应用程序，并支持快速启动运行。</li>
<li><strong>Spring Data</strong>：提供一致的数据访问方法-关系型、非关系型、Map-Reduce等。</li>
<li><strong>Spring Cloud</strong>：为分布式系统中的常见模式提供一组工具，可用于构建和部署微服务。</li>
<li><strong>Spring Cloud Data Flow</strong>：为现运行上的可组合数据微服务应用程序提供编排服务。</li>
<li><strong>Spring Security</strong>：通过全面且可扩展的身份验证和授权支持来保护应用程序。</li>
<li><strong>Spring Authorization Server</strong>：为构建 OpenID Connect 1.0 身份提供程序和 OAuth2 授权服务器产品提供安全、轻量级和可自定义的基础服务。</li>
<li><strong>Spring for GraphQL</strong>：为基于 GraphQL Java 构建的 Spring 应用程序提供支持。</li>
<li><strong>Spring Session</strong>：提供用于管理用户回话信息的API和实现。</li>
<li><strong>Spring Integration</strong>：通过轻量级信息传递和声明性适配器支持众所周知的企业继承模式。</li>
<li><strong>Spring HATEOAS</strong>：简化了遵循 HATEOAS 原则的 REST 表示形式的创建。</li>
<li><strong>Spring Modulith</strong>：允许开发人员构建结构良好的 Spring Boot 应用程序，并指导开发人员查找和使用由域驱动的应用程序模块。</li>
<li><strong>Spring REST Docs</strong>：允许通过手写文档与使用 Spring MVC Test 或 REST Assured 生成的自动生成的代码片段相结合来记录 RESTful 服务。</li>
<li><strong>Spring AI</strong>：Spring AI 是 AI 工程的应用框架。</li>
<li><strong>Spring Batch</strong>：简化和优化处理大批量批处理操作的工作。</li>
<li><strong>Spring CLI</strong>：专注于开发人员生产力的 CLI。</li>
<li><strong>Spring AMQP</strong>：将核心 Spring 概念应用于基于 AMQP 的消息传递解决方案的开发。</li>
<li><strong>Spring for Apache Kafka</strong>：为 Apache Kafka 提供熟悉的 Spring Abstract。</li>
<li><strong>pPring LDAP</strong> ：通过使用 Spring 熟悉的基于模板的方法缉拿花了使用 LDAP 的应用程序的开发。</li>
<li><strong>Spring for Apache Pulsar</strong>：为 Apache Pulsar 提供熟悉的 Spring Abastract。</li>
<li><strong>Spring Shell</strong>：通过基于 CLI 的资源发现和交互，使编写和测试 RESTful 应用程序变得更加容易。</li>
<li><strong>Spring Statemachine</strong>：为应用程序开发人员提供一个框架，以便将Statemachine（状态机）概念用于 Spring 应用程序。</li>
<li><strong>Spring Web Flow</strong>：支持构建具有受控导航功能的 Web 应用程序，例如办理登记手续或者申请贷款。</li>
<li><strong>Spring Web Services</strong>：促进合同有限的 SOAP Web 服务的开发。</li>
</ol>
<h2 id="2、Spring-Boot"><a href="#2、Spring-Boot" class="headerlink" title="2、Spring Boot"></a>2、Spring Boot</h2><p><a target="_blank" rel="noopener" href="https://spring.io/projects/spring-boot">Spring Boot</a>可以帮助我们非常快速的构建应用程序、简化开发、提高效率。</p>
<h3 id="Spring-Boot-Web-快速入门案例"><a href="#Spring-Boot-Web-快速入门案例" class="headerlink" title="Spring Boot Web 快速入门案例"></a>Spring Boot Web 快速入门案例</h3><p><strong>需求描述：</strong>使用Spring Boot 开发一个 Web 应用，使浏览器发起请求 &#x2F;hello 后，给浏览器返回字符串 “Hello World”。</p>
<p><strong>实现步骤（3步）</strong>：</p>
<ol>
<li><strong>创建 Spring Boot 工程，并勾选 Web 开发相关依赖。</strong></li>
<li><strong>定义 Hello Controller类，添加方法 hello，并添加注解。</strong></li>
<li><strong>运行测试。</strong></li>
</ol>
<p>测试环境：</p>
<ul>
<li>win10</li>
<li>JDK17</li>
<li>IDEA Utimate 2021.1.3</li>
</ul>
<p><img src="https://uni-pic-bed.oss-cn-hangzhou.aliyuncs.com/blog2024/202403110308926.png" srcset="/img/loading.gif" lazyload alt="image-20240311030804811"></p>
<p><code>注：上图中项目 SDK 最低选择 JDK17（图中的1.8后面修改为17了）因为 Spring Boot 目前支持的最低版本是 JDK17，如果是老项目的话，可以先创建然后再修改 项目设置和 Maven依赖。另外，上面的groupId起反了，一般是cn.ccuni像这样倒着表示，不过没关系后续可以直接改目录文件和Maven的配置。</code></p>
<p><img src="https://uni-pic-bed.oss-cn-hangzhou.aliyuncs.com/blog2024/202403110311565.png" srcset="/img/loading.gif" lazyload alt="image-20240311031159486"></p>
<p>项目创建后，有些文件是暂时用不到的，可以直接删除。</p>
<img src="https://uni-pic-bed.oss-cn-hangzhou.aliyuncs.com/blog2024/202403110315686.png" srcset="/img/loading.gif" lazyload alt="image-20240311031501616" style="zoom:50%;" />

<p>删除后，确认 Spring Boot 的启动类是否存在。</p>
<p><img src="https://uni-pic-bed.oss-cn-hangzhou.aliyuncs.com/blog2024/202403110330865.png" srcset="/img/loading.gif" lazyload alt="image-20240311033002742"></p>
<p>接下来编写 Controller 层的接口 </p>
<p><img src="https://uni-pic-bed.oss-cn-hangzhou.aliyuncs.com/blog2024/202403110332470.png" srcset="/img/loading.gif" lazyload alt="image-20240311033213368"></p>
<p>最终测试结果：</p>
<p><img src="https://uni-pic-bed.oss-cn-hangzhou.aliyuncs.com/blog2024/202403110333463.png" srcset="/img/loading.gif" lazyload alt="image-20240311033352425"></p>
<h2 id="3、HTTP-协议"><a href="#3、HTTP-协议" class="headerlink" title="3、HTTP 协议"></a>3、HTTP 协议</h2><h3 id="3-1-HTTP-概述"><a href="#3-1-HTTP-概述" class="headerlink" title="3.1 HTTP 概述"></a>3.1 HTTP 概述</h3><p><code>HTTP</code> （Hyper Text Transfer Protocol）即超文本传输协议，规定了<strong>浏览器</strong>和<strong>服务器</strong>之间数据传输的规则，主要就是规范了浏览器<strong>请求</strong>与服务器<strong>响应</strong>的数据格式。</p>
<p><strong>HTTP 协议的特点：</strong></p>
<ol>
<li><strong>基于 TCP协议：</strong>面向连接，安全。</li>
<li><strong>基于请求-响应模型的：</strong>一次请求对应一次响应。</li>
<li><strong>无状态协议：</strong>对于事务处理没有记忆力，每次请求和响应都是独立的。<ul>
<li>缺点：多次请求之间无法共享数据。</li>
<li>优点：速度快。</li>
</ul>
</li>
</ol>
<h3 id="3-2-HTTP-请求协议"><a href="#3-2-HTTP-请求协议" class="headerlink" title="3.2 HTTP 请求协议"></a>3.2 HTTP 请求协议</h3><p>HTTP 请求的数据格式在我们用浏览器访问网页时，可在浏览器调试工具中的网络中查看到，一般是按F12打开，如下图：</p>
<p><img src="https://uni-pic-bed.oss-cn-hangzhou.aliyuncs.com/blog2024/202403110349732.png" srcset="/img/loading.gif" lazyload alt="image-20240311034914512"></p>
<p>HTTP请求的数据格式如下，是典型的JSON格式。</p>
<p><img src="https://uni-pic-bed.oss-cn-hangzhou.aliyuncs.com/blog2024/202403110357194.png" srcset="/img/loading.gif" lazyload alt="image-20240311035740104"></p>
<p><strong>其中主要有3个部分：</strong></p>
<ol>
<li><strong>请求行：</strong>请求数据第一行（请求方式、资源路径、协议）。</li>
<li><strong>请求头：</strong>第二行开始，格式 key：value。</li>
<li><strong>请求体：</strong>POST请求，存放请求参数。</li>
</ol>
<p>常见属性有：</p>
<table>
<thead>
<tr>
<th>属性</th>
<th>含义</th>
</tr>
</thead>
<tbody><tr>
<td>Host</td>
<td>请求的主机名</td>
</tr>
<tr>
<td>User-Agent</td>
<td>浏览器版本，例如Chrome浏览器的标识类类似 Mozilla&#x2F;5.0 … Chrome&#x2F;79 ，IE浏览器的标识类似 Mozilla &#x2F;5.0 (WIndows NT …)</td>
</tr>
<tr>
<td>Accept</td>
<td>表示浏览器能接收的资源类型，如<code>text/*，</code>image&#x2F;* &#96;或者<code>*/*</code> 表示所有</td>
</tr>
<tr>
<td>Accept - Language</td>
<td>表示浏览器偏好的语言，服务器可以据此返回不同语言的网页</td>
</tr>
<tr>
<td>Accept - Encoding</td>
<td>表示浏览器可以支持的压缩类型，例如 gzip，deflate 等</td>
</tr>
<tr>
<td>Content - Type</td>
<td>请求主体的数据类型</td>
</tr>
<tr>
<td>Content - Length</td>
<td>请求主体的大小（单位：Byte，即字节）</td>
</tr>
</tbody></table>
<p>HTTP 请求方式最常见的是 <code>GET</code> 和 <code>POST</code> 这两种。</p>
<ul>
<li><strong>请求方式 - GET：</strong>请求参数在请求行中，没有请求体，如：<code>/user/findUser?id=1</code>，GET请求大小是有限制的。</li>
<li><strong>请求方式 - POST：</strong> 请求参数在<strong>请求体</strong>中，POST 请求大小是没有限制的。</li>
</ul>
<h3 id="3-3-HTTP-响应协议"><a href="#3-3-HTTP-响应协议" class="headerlink" title="3.3 HTTP 响应协议"></a>3.3 HTTP 响应协议</h3><p>HTTP 响应协议就是指 HTTP 响应数据格式。</p>
<p>HTTP响应的数据格式如下，同样是典型的 JSON 格式：</p>
<p><img src="https://uni-pic-bed.oss-cn-hangzhou.aliyuncs.com/blog2024/202403110406639.png" srcset="/img/loading.gif" lazyload alt="image-20240311040631582"></p>
<p><strong>其中主要有3个部分：</strong></p>
<ol>
<li><strong>响应行：</strong> 响应数据第一行（协议、状态码、描述）。</li>
<li><strong>响应头：</strong> 第二行开始，格式 key : value。</li>
<li><strong>响应体：</strong> 最后一部分，存放响应数据。</li>
</ol>
<h4 id="响应状态码"><a href="#响应状态码" class="headerlink" title="响应状态码"></a>响应状态码</h4><p>HTTP 响应协议中的<strong>响应状态码分类</strong>有以下5种：</p>
<table>
<thead>
<tr>
<th>状态码分类</th>
<th>描述</th>
</tr>
</thead>
<tbody><tr>
<td>1xx</td>
<td>响应中-临时状态码，表示请求已经接收，告诉客户端应该继续请求，若已完成请求则忽略。</td>
</tr>
<tr>
<td>2xx</td>
<td>成功-表示请求已经被成功接收，处理已完成。</td>
</tr>
<tr>
<td>3xx</td>
<td>重定向-重定向到其他地方；让客户端再发起一次请求以完成整个处理。</td>
</tr>
<tr>
<td>4xx</td>
<td>客户端错误-处理发生错误，责任在客户端，如：404表示请求了不存在的资源，客户端未被授权、禁止访问等</td>
</tr>
<tr>
<td>5xx</td>
<td>服务器错误-处理发生错误，责任在服务器，如：程序抛出异常等。</td>
</tr>
</tbody></table>
<p><strong>常见的响应状态码：</strong></p>
<p><img src="https://uni-pic-bed.oss-cn-hangzhou.aliyuncs.com/blog2024/202403110419104.png" srcset="/img/loading.gif" lazyload alt="image-20240311041931966"></p>
<p>需要掌握的三个响应状态码：</p>
<ul>
<li><strong>200：</strong>客户端请求成功。</li>
<li><strong>404：</strong>请求资源不存在，一般是请求的URL有误，或者网站资源被删除。</li>
<li><strong>500：</strong>服务器发生不可预期的错误。</li>
</ul>
<h4 id="HTTP-响应属性"><a href="#HTTP-响应属性" class="headerlink" title="HTTP 响应属性"></a>HTTP 响应属性</h4><p><strong>其他的常见响应属性有：</strong></p>
<table>
<thead>
<tr>
<th>属性</th>
<th>描述</th>
</tr>
</thead>
<tbody><tr>
<td>Content-Type</td>
<td>表示该响应内容的类型，例如：text。</td>
</tr>
<tr>
<td>Content-Length</td>
<td>表示该响应内容的长度（字节数）。</td>
</tr>
<tr>
<td>Content-Encoding</td>
<td>表示该响应压缩算法，例如 gzip。</td>
</tr>
<tr>
<td>Cache-Control</td>
<td>指示客户端应如何缓存，例如：max-age &#x3D; 300表示最多可以缓存 300 秒。</td>
</tr>
<tr>
<td>Set-Cookie</td>
<td>告诉浏览器为当前页面所在的域设置 cookie。</td>
</tr>
</tbody></table>
<h3 id="3-4-HTTP-协议解析案例"><a href="#3-4-HTTP-协议解析案例" class="headerlink" title="3.4 HTTP 协议解析案例"></a>3.4 HTTP 协议解析案例</h3><p> <code>HTTP</code>（Hyper Text Transfer Protocol）超文本协议规定了浏览器和服务器之间数据传输的规则。</p>
<p>那么对于HTTP协议解析主要就由客户端-浏览器和服务端这两个来解决。而浏览器已经内置了解析HTTP协议的程序，不需要我们去操作。</p>
<p>作为 Web 开发人员，主要就是在后端，使用 Java 程序来接收客户端-浏览器发起的请求并获取请求数据，然后根据请求数据格式对请求数据进行解析，最后按照HTTP响应数据的格式给浏览器响应对应的数据。</p>
<p><strong>案例：使用 Java Scoket套接字模拟一个 WEB 服务端处理8080端口的GET请求</strong>，</p>
<p><strong>项目结构：</strong></p>
<img src="https://uni-pic-bed.oss-cn-hangzhou.aliyuncs.com/blog2024/202403110951214.png" srcset="/img/loading.gif" lazyload alt="image-20240311095152107" style="zoom:50%;" />

<p><code>Server.java</code></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">package</span> cn.uni;<br><span class="hljs-comment">/*-----------------------------------</span><br><span class="hljs-comment"> *   @Author: uni</span><br><span class="hljs-comment"> *   @Time: 2024/3/11 9:06</span><br><span class="hljs-comment"> *   @Description:</span><br><span class="hljs-comment">-----------------------------------*/</span><br><br><span class="hljs-keyword">import</span> java.io.*;<br><span class="hljs-keyword">import</span> java.net.ServerSocket;<br><span class="hljs-keyword">import</span> java.net.Socket;<br><span class="hljs-keyword">import</span> java.nio.charset.StandardCharsets;<br><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">Server</span> &#123;<br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">main</span><span class="hljs-params">(String[] args)</span> <span class="hljs-keyword">throws</span> IOException &#123;<br>        <span class="hljs-type">ServerSocket</span> <span class="hljs-variable">ss</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">ServerSocket</span>(<span class="hljs-number">8080</span>);<br>        System.out.println(<span class="hljs-string">&quot;[WEB服务器] 服务器已启动&quot;</span>);<br><br>        <span class="hljs-keyword">while</span>(<span class="hljs-literal">true</span>)&#123;<br>            <span class="hljs-comment">// 等待连接</span><br>            <span class="hljs-type">Socket</span> <span class="hljs-variable">socket</span> <span class="hljs-operator">=</span> ss.accept();<br>            System.out.println(<span class="hljs-string">&quot;[WEB服务器] 接收到了连接, 地址为: &quot;</span> + socket.getRemoteSocketAddress());<br>            <span class="hljs-comment">// 启动一个线程处理请求</span><br>            <span class="hljs-type">Handler</span> <span class="hljs-variable">handler</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Handler</span>(socket);<br>            handler.start();<br>        &#125;<br>    &#125;<br>&#125;<br><span class="hljs-comment">// 定义一个线程类</span><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Handler</span> <span class="hljs-keyword">extends</span> <span class="hljs-title class_">Thread</span>&#123;<br>    Socket socket;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-title function_">Handler</span><span class="hljs-params">(Socket socket)</span>&#123;<br>        <span class="hljs-built_in">this</span>.socket = socket;<br>    &#125;<br><br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">run</span><span class="hljs-params">()</span> &#123;<br>        <span class="hljs-keyword">try</span>(<span class="hljs-type">InputStream</span> <span class="hljs-variable">input</span> <span class="hljs-operator">=</span> <span class="hljs-built_in">this</span>.socket.getInputStream();<br>            <span class="hljs-type">OutputStream</span> <span class="hljs-variable">output</span> <span class="hljs-operator">=</span> <span class="hljs-built_in">this</span>.socket.getOutputStream()) &#123;<br>            handle(input, output);<br>        &#125; <span class="hljs-keyword">catch</span> (IOException e) &#123;<br>            <span class="hljs-keyword">try</span>&#123;<br>                <span class="hljs-built_in">this</span>.socket.close();<br>            &#125; <span class="hljs-keyword">catch</span> (IOException exception)&#123;&#125;<br>            System.out.println(<span class="hljs-string">&quot;[WEB服务器] 客户端断开连接&quot;</span>);<br>        &#125;<br>    &#125;<br><br>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">handle</span><span class="hljs-params">(InputStream input, OutputStream output)</span> <span class="hljs-keyword">throws</span> IOException&#123;<br>        <span class="hljs-type">BufferedReader</span> <span class="hljs-variable">reader</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">BufferedReader</span>(<span class="hljs-keyword">new</span> <span class="hljs-title class_">InputStreamReader</span>(input, StandardCharsets.UTF_8));<br>        <span class="hljs-type">OutputStreamWriter</span> <span class="hljs-variable">writer</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">OutputStreamWriter</span>(output, StandardCharsets.UTF_8);<br>        <span class="hljs-comment">// 读取 HTTP 请求</span><br>        <span class="hljs-type">boolean</span> <span class="hljs-variable">requestOK</span> <span class="hljs-operator">=</span> <span class="hljs-literal">false</span>;<br>        <span class="hljs-type">String</span> <span class="hljs-variable">first</span> <span class="hljs-operator">=</span> reader.readLine();<br>        <span class="hljs-keyword">if</span>(first.startsWith(<span class="hljs-string">&quot;GET / HTTP/1.&quot;</span>))&#123;<br>            requestOK = <span class="hljs-literal">true</span>;<br>        &#125;<br>        <span class="hljs-comment">// 读取请求头并输出</span><br>        <span class="hljs-keyword">for</span>(;;)&#123;<br>            <span class="hljs-type">String</span> <span class="hljs-variable">header</span> <span class="hljs-operator">=</span> reader.readLine();<br>            <span class="hljs-comment">// 读取到空行时，HTTP Header 读取完毕, 退出循环</span><br>            <span class="hljs-keyword">if</span>(header.isEmpty()) &#123; <span class="hljs-keyword">break</span>;&#125;<br>            System.out.println(<span class="hljs-string">&quot;[WEB服务器] &quot;</span> + header);<br>        &#125;<br>        System.out.println(requestOK ? <span class="hljs-string">&quot;[WEB服务器] 请求成功&quot;</span> : <span class="hljs-string">&quot;[WEB服务器] 请求错误&quot;</span>);<br><br>        <span class="hljs-comment">// 如果请求失败, 则发送错误的响应</span><br>        <span class="hljs-keyword">if</span>(!requestOK)&#123;<br>            writer.write(<span class="hljs-string">&quot;HTTP/1.0 404 Not Found\r\n&quot;</span>);<br>            writer.write(<span class="hljs-string">&quot;Content-Length: 0\r\n&quot;</span>);<br>            writer.write(<span class="hljs-string">&quot;\r\n&quot;</span>);<br>            writer.flush();<br>        &#125; <span class="hljs-keyword">else</span>&#123;  <span class="hljs-comment">// 请求成功则发送成功响应</span><br>            <span class="hljs-comment">// 读取 html 文件, 转换为字符串</span><br>            <span class="hljs-type">InputStream</span> <span class="hljs-variable">is</span> <span class="hljs-operator">=</span> Server.class.getClassLoader().getResourceAsStream(<span class="hljs-string">&quot;html/a.html&quot;</span>);<br>            <span class="hljs-type">BufferedReader</span> <span class="hljs-variable">br</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">BufferedReader</span>(<span class="hljs-keyword">new</span> <span class="hljs-title class_">InputStreamReader</span>(is));<br>            <span class="hljs-type">StringBuilder</span> <span class="hljs-variable">data</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">StringBuilder</span>();<br>            <span class="hljs-type">String</span> <span class="hljs-variable">line</span> <span class="hljs-operator">=</span> <span class="hljs-literal">null</span>;<br>            <span class="hljs-keyword">while</span>((line = br.readLine()) != <span class="hljs-literal">null</span>) &#123;<br>                data.append(line);<br>            &#125;<br>            br.close();<br>            <span class="hljs-type">int</span> <span class="hljs-variable">length</span> <span class="hljs-operator">=</span> data.toString().getBytes(StandardCharsets.UTF_8).length;<br>            writer.write(<span class="hljs-string">&quot;HTTP/1.1 200 OK\r\n&quot;</span>);<br>            writer.write(<span class="hljs-string">&quot;Connection: keep-alive\r\n&quot;</span>);<br>            writer.write(<span class="hljs-string">&quot;Content-Type: text/html\r\n&quot;</span>);<br>            writer.write(<span class="hljs-string">&quot;\r\n&quot;</span>); <span class="hljs-comment">// 空行是为了标识 响应头和响应体</span><br>            writer.write(data.toString());<br>            writer.flush();<br>        &#125;<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<p>项目中的 <code>a.html</code> 作为响应的结果返回</p>
<p><code>a.html</code></p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs html"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-keyword">html</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">&quot;en&quot;</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">&quot;UTF-8&quot;</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>响应页面<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>这是来自WEB服务器的页面<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span><br></code></pre></td></tr></table></figure>

<p>测试结果：</p>
<p><img src="https://uni-pic-bed.oss-cn-hangzhou.aliyuncs.com/blog2024/202403110949742.png" srcset="/img/loading.gif" lazyload alt="image-20240311094845200"></p>
<h2 id="4、Web-服务器"><a href="#4、Web-服务器" class="headerlink" title="4、Web 服务器"></a>4、Web 服务器</h2><p>Web 服务器是一个软件程序，主要对 HTTP 协议的操作进行<strong>封装</strong>，使得开发人员不必直接对协议进行操作，让 Web开发更加便捷，主要功能是“<strong>提供网上信息浏览服务</strong>”。</p>
<h3 id="Tomcat-服务器"><a href="#Tomcat-服务器" class="headerlink" title="Tomcat 服务器"></a>Tomcat 服务器</h3><p><a target="_blank" rel="noopener" href="https://tomcat.apache.org/">Apache Tomcat 官网</a></p>
<p>Tomcat  是Apache 软件基金会的一个核心项目，是一个<strong>开源免费的轻量级Web服务器</strong>，支持 Servlet &#x2F; JSP <strong>少量</strong> JavaEE 规范。</p>
<figure class="highlight mipsasm"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs mipsasm"><span class="hljs-keyword">JavaEE即 </span><span class="hljs-keyword">Java </span>Enterprise Edition，<span class="hljs-keyword">Java </span>企业版，指<span class="hljs-keyword">Java企业级开发的技术规范总和。包含13项技术规范，分别是：JDBC、JNDI、Ej8、RMI、JSP、Servlet、XML、JMS、Java </span>IDL、<span class="hljs-keyword">JTS、JTA、JavaMail、JAF。</span><br><span class="hljs-keyword"></span><br>其他两个还有<span class="hljs-keyword">JavaSE即Java标准版和JavaME即Java小型版，</span><br></code></pre></td></tr></table></figure>

<p>Tomcat 也被称为 Web 容器，Servlet 容器， Servlet 程序需要依赖于 Tomcat 才能运行。</p>
<p><strong>Tomcat 的基本使用</strong></p>
<ol>
<li><p>下载 Tomcat，地址：<a target="_blank" rel="noopener" href="https://tomcat.apache.org/download-90.cgi">Apache Tomcat® - Apache Tomcat 9 Software Downloads</a></p>
<img src="https://uni-pic-bed.oss-cn-hangzhou.aliyuncs.com/blog2024/202403111017937.png" srcset="/img/loading.gif" lazyload alt="image-20240311101758743" style="zoom:80%;" /></li>
</ol>
<p>解压后的 Tomcat 文件目录如下：</p>
<img src="https://uni-pic-bed.oss-cn-hangzhou.aliyuncs.com/blog2024/202403111757052.png" srcset="/img/loading.gif" lazyload alt="image-20240311175758983" style="zoom:80%;" />



<p>在启动前，为解决Tomcat的日志信息在控制台输出的中文出现乱码，需要在<code>conf/logging.properties</code>文件中修改指定的配置：</p>
<p>修改前</p>
<figure class="highlight properties"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs properties"><span class="hljs-attr">java.util.logging.ConsoleHandler.encoding</span> = <span class="hljs-string">UTF-8</span><br></code></pre></td></tr></table></figure>

<p>修改后</p>
<figure class="highlight properties"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs properties"><span class="hljs-attr">java.util.logging.ConsoleHandler.encoding</span> = <span class="hljs-string">GBK</span><br></code></pre></td></tr></table></figure>

<p><strong>关于 Tomcat 的几个基本操作：</strong></p>
<ul>
<li><p><strong>下载：</strong>官网下载，地址：<a target="_blank" rel="noopener" href="https://tomcat.apache.org/download-90.cgi">Apache Tomcat® - Apache Tomcat 9 Software Downloads</a>。</p>
</li>
<li><p><strong>安装：</strong>下载zip压缩包后解压到本地目录即可。</p>
</li>
<li><p><strong>卸载：</strong>直接删除目录即可</p>
</li>
<li><p><strong>启动：</strong>windows系统中启动 bin 目录下的 startup.bat。</p>
</li>
<li><p><strong>关闭：</strong></p>
<ul>
<li><strong>强制关闭：</strong>直接关掉 Tomcat 的运行窗口。</li>
<li><strong>正常关闭：</strong>启动 bin 目录中的 shutdown.bat。</li>
<li><strong>正常关闭：</strong>控制台内使用快捷键 Ctrl + C。</li>
</ul>
</li>
<li><p><strong>修改端口号：</strong>在 conf目录下的 <code>server.xml</code>中修改<code>&lt;Connector&gt;</code> 标签内的 port 属性值即可，修改后需重启 Tomcat。</p>
<p><code>注：HTTP协议默认端口号为80，若将Tomcat 端口号改为80，则访问 Tomcat 时，将不用输入端口号。</code></p>
</li>
<li><p><strong>Tomcat 部署项目：</strong> 将项目放置到 <code>webapps</code> 目录下，即部署完成。</p>
</li>
</ul>
<h2 id="5、Spring-Boot-Web-入门程序解析"><a href="#5、Spring-Boot-Web-入门程序解析" class="headerlink" title="5、Spring Boot Web - 入门程序解析"></a>5、Spring Boot Web - 入门程序解析</h2><p><img src="https://uni-pic-bed.oss-cn-hangzhou.aliyuncs.com/blog2024/202403111818177.png" srcset="/img/loading.gif" lazyload alt="image-20240311181805083"></p>
<p>Spring Boot 具有如下的<strong>起步依赖：</strong></p>
<ul>
<li><code>spring-boot-starter-web</code>：包含了 web 应用开发所需要的常见依赖。</li>
<li><code>spring-boot-starter-test</code>：包含了单元测试所需要的常见依赖。</li>
</ul>
<p>官方对 <code>starter</code> 起步依赖的说明：<a target="_blank" rel="noopener" href="https://docs.spring.io/spring-boot/docs/3.2.3/reference/htmlsingle/#using.build-systems.starters">Spring Boot Reference Documentation</a></p>
<p>Spring Boot 内嵌了 Tomcat 服务器，当启动类运行时，会自动启动内嵌的 Tomcat 服务器。</p>
<p>请求响应：</p>
<ul>
<li>请求（HttpServletRequest）：获取请求数据</li>
<li>响应（HttpServletResponse）：设置响应数据</li>
<li>BS 架构：Browser &#x2F; Server ,浏览器 &#x2F; 服务器架构模式。客户端只需要浏览器，应用程序的逻辑和数据都存储在服务器（维护方便，体验一般）。</li>
<li>CS架构：Client &#x2F; Server，客户端 &#x2F; 服务器架构模式。（开发、维护麻烦，体验不错）。</li>
</ul>
<h2 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h2><p><a target="_blank" rel="noopener" href="https://www.bilibili.com/video/BV1m84y1w7Tb?p=59&spm_id_from=pageDriver&vd_source=b4ec95b69d71f383dd1bea5519d7a841">Day04-10. Web入门-SpringBootWeb-快速入门_哔哩哔哩_bilibili</a></p>

                
              </div>
            
            <hr/>
            <div>
              <div class="post-metas my-3">
  
    <div class="post-meta mr-3 d-flex align-items-center">
      <i class="iconfont icon-category"></i>
      

<span class="category-chains">
  
  
    
      <span class="category-chain">
        
  <a href="/categories/Web%E5%BC%80%E5%8F%91/" class="category-chain-item">Web开发</a>
  
  

      </span>
    
  
</span>

    </div>
  
  
    <div class="post-meta">
      <i class="iconfont icon-tags"></i>
      
        <a href="/tags/Web/" class="print-no-link">#Web</a>
      
        <a href="/tags/SpringBoot/" class="print-no-link">#SpringBoot</a>
      
        <a href="/tags/HTTP/" class="print-no-link">#HTTP</a>
      
        <a href="/tags/Tomcat/" class="print-no-link">#Tomcat</a>
      
    </div>
  
</div>


              
  

  <div class="license-box my-3">
    <div class="license-title">
      <div>Web 开发笔记2 | 后端 Spring Boot、HTTP协议、Web服务器、Tomcat</div>
      <div>http://example.com/2024/03/11/Web开发笔记2-后端-Spring-Boot、HTTP协议、Web服务器、Tomcat/</div>
    </div>
    <div class="license-meta">
      
        <div class="license-meta-item">
          <div>作者</div>
          <div>十一的蛋炒饭</div>
        </div>
      
      
        <div class="license-meta-item license-meta-date">
          <div>发布于</div>
          <div>2024年3月11日</div>
        </div>
      
      
      
        <div class="license-meta-item">
          <div>许可协议</div>
          <div>
            
              
              
                <a class="print-no-link" target="_blank" href="https://creativecommons.org/licenses/by/4.0/">
                  <span class="hint--top hint--rounded" aria-label="BY - 署名">
                    <i class="iconfont icon-by"></i>
                  </span>
                </a>
              
            
          </div>
        </div>
      
    </div>
    <div class="license-icon iconfont"></div>
  </div>



              
                <div class="post-prevnext my-3">
                  <article class="post-prev col-6">
                    
                    
                      <a href="/2024/03/11/BUG%E8%AE%B0%E5%BD%9513-SpringBoot-%E7%BC%96%E5%86%99%E6%8E%A5%E5%8F%A3%E6%97%B6%E6%8E%A5%E6%94%B6%E4%B8%8D%E5%88%B0%E5%A4%8D%E6%9D%82%E7%9A%84%E5%8F%82%E6%95%B0%E7%B1%BB%E5%9E%8B/" title="BUG记录13 | SpringBoot 编写接口时接收不到复杂的参数类型">
                        <i class="iconfont icon-arrowleft"></i>
                        <span class="hidden-mobile">BUG记录13 | SpringBoot 编写接口时接收不到复杂的参数类型</span>
                        <span class="visible-mobile">上一篇</span>
                      </a>
                    
                  </article>
                  <article class="post-next col-6">
                    
                    
                      <a href="/2024/03/10/Maven-%E7%AC%94%E8%AE%B01-%E7%AE%80%E4%BB%8B%E3%80%81%E5%AE%89%E8%A3%85%E3%80%81%E5%9D%90%E6%A0%87%E3%80%81%E4%BE%9D%E8%B5%96%E7%AE%A1%E7%90%86%E3%80%81%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F/" title="Maven 笔记1 | 简介、安装、坐标、依赖管理、生命周期">
                        <span class="hidden-mobile">Maven 笔记1 | 简介、安装、坐标、依赖管理、生命周期</span>
                        <span class="visible-mobile">下一篇</span>
                        <i class="iconfont icon-arrowright"></i>
                      </a>
                    
                  </article>
                </div>
              
            </div>

            
          </article>
        </div>
      </div>
    </div>

    <div class="side-col d-none d-lg-block col-lg-2">
      
  <aside class="sidebar" style="margin-left: -1rem">
    <div id="toc">
  <p class="toc-header">
    <i class="iconfont icon-list"></i>
    <span>目录</span>
  </p>
  <div class="toc-body" id="toc-body"></div>
</div>



  </aside>


    </div>
  </div>
</div>





  



  



  



  



  







    

    
      <a id="scroll-top-button" aria-label="TOP" href="#" role="button">
        <i class="iconfont icon-arrowup" aria-hidden="true"></i>
      </a>
    

    
      <div class="modal fade" id="modalSearch" tabindex="-1" role="dialog" aria-labelledby="ModalLabel"
     aria-hidden="true">
  <div class="modal-dialog modal-dialog-scrollable modal-lg" role="document">
    <div class="modal-content">
      <div class="modal-header text-center">
        <h4 class="modal-title w-100 font-weight-bold">搜索</h4>
        <button type="button" id="local-search-close" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
      </div>
      <div class="modal-body mx-3">
        <div class="md-form mb-5">
          <input type="text" id="local-search-input" class="form-control validate">
          <label data-error="x" data-success="v" for="local-search-input">关键词</label>
        </div>
        <div class="list-group" id="local-search-result"></div>
      </div>
    </div>
  </div>
</div>

    

    
  </main>

  <footer>
    <div class="footer-inner">
  
    <div class="footer-content">
       <a href="https://hexo.io" target="_blank" rel="nofollow noopener"><span>博客网站基于Hexo</span></a> <i class="iconfont icon-love"></i> <a href="https://github.com/fluid-dev/hexo-theme-fluid" target="_blank" rel="nofollow noopener"><span>主题Fluid</span></a> 
    </div>
  
  
  
  
</div>

  </footer>

  <!-- Scripts -->
  
  <script  src="https://lib.baomitu.com/nprogress/0.2.0/nprogress.min.js" ></script>
  <link  rel="stylesheet" href="https://lib.baomitu.com/nprogress/0.2.0/nprogress.min.css" />

  <script>
    NProgress.configure({"showSpinner":false,"trickleSpeed":100})
    NProgress.start()
    window.addEventListener('load', function() {
      NProgress.done();
    })
  </script>


<script  src="https://lib.baomitu.com/jquery/3.6.4/jquery.min.js" ></script>
<script  src="https://lib.baomitu.com/twitter-bootstrap/4.6.1/js/bootstrap.min.js" ></script>
<script  src="/js/events.js" ></script>
<script  src="/js/plugins.js" ></script>





  
    <script  src="/js/img-lazyload.js" ></script>
  




  
<script>
  var relativeDate = function() {
    var updatedTime = document.getElementById('updated-time');
    if (updatedTime) {
      var text = updatedTime.textContent;
      var reg = /\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:Z|[+-]\d{2}:\d{2})/;
      var matchs = text.match(reg);
      if (matchs) {
        var relativeTime = moment(matchs[0]).fromNow();
        updatedTime.textContent = text.replace(reg, relativeTime);
      }
      updatedTime.style.display = '';
    }
  };
  Fluid.utils.createScript('https://lib.baomitu.com/moment.js/2.29.4/moment.min.js', function() {
    if (!'zh-cn'.startsWith('en')) {
      Fluid.utils.createScript('https://lib.baomitu.com/moment.js/2.29.4/locale/zh-cn.min.js', function() {
        relativeDate();
      });
    } else {
      relativeDate();
    }
  });
</script>


  
<script>
  Fluid.utils.createScript('https://lib.baomitu.com/tocbot/4.20.1/tocbot.min.js', function() {
    var toc = jQuery('#toc');
    if (toc.length === 0 || !window.tocbot) { return; }
    var boardCtn = jQuery('#board-ctn');
    var boardTop = boardCtn.offset().top;

    window.tocbot.init(Object.assign({
      tocSelector     : '#toc-body',
      contentSelector : '.markdown-body',
      linkClass       : 'tocbot-link',
      activeLinkClass : 'tocbot-active-link',
      listClass       : 'tocbot-list',
      isCollapsedClass: 'tocbot-is-collapsed',
      collapsibleClass: 'tocbot-is-collapsible',
      scrollSmooth    : true,
      includeTitleTags: true,
      headingsOffset  : -boardTop,
    }, CONFIG.toc));
    if (toc.find('.toc-list-item').length > 0) {
      toc.css('visibility', 'visible');
    }

    Fluid.events.registerRefreshCallback(function() {
      if ('tocbot' in window) {
        tocbot.refresh();
        var toc = jQuery('#toc');
        if (toc.length === 0 || !tocbot) {
          return;
        }
        if (toc.find('.toc-list-item').length > 0) {
          toc.css('visibility', 'visible');
        }
      }
    });
  });
</script>


  <script src=https://lib.baomitu.com/clipboard.js/2.0.11/clipboard.min.js></script>

  <script>Fluid.plugins.codeWidget();</script>


  
<script>
  Fluid.utils.createScript('https://lib.baomitu.com/anchor-js/4.3.1/anchor.min.js', function() {
    window.anchors.options = {
      placement: CONFIG.anchorjs.placement,
      visible  : CONFIG.anchorjs.visible
    };
    if (CONFIG.anchorjs.icon) {
      window.anchors.options.icon = CONFIG.anchorjs.icon;
    }
    var el = (CONFIG.anchorjs.element || 'h1,h2,h3,h4,h5,h6').split(',');
    var res = [];
    for (var item of el) {
      res.push('.markdown-body > ' + item.trim());
    }
    if (CONFIG.anchorjs.placement === 'left') {
      window.anchors.options.class = 'anchorjs-link-left';
    }
    window.anchors.add(res.join(', '));

    Fluid.events.registerRefreshCallback(function() {
      if ('anchors' in window) {
        anchors.removeAll();
        var el = (CONFIG.anchorjs.element || 'h1,h2,h3,h4,h5,h6').split(',');
        var res = [];
        for (var item of el) {
          res.push('.markdown-body > ' + item.trim());
        }
        if (CONFIG.anchorjs.placement === 'left') {
          anchors.options.class = 'anchorjs-link-left';
        }
        anchors.add(res.join(', '));
      }
    });
  });
</script>


  
<script>
  Fluid.utils.createScript('https://lib.baomitu.com/fancybox/3.5.7/jquery.fancybox.min.js', function() {
    Fluid.plugins.fancyBox();
  });
</script>


  <script>Fluid.plugins.imageCaption();</script>

  <script  src="/js/local-search.js" ></script>





<!-- 主题的启动项，将它保持在最底部 -->
<!-- the boot of the theme, keep it at the bottom -->
<script  src="/js/boot.js" ></script>


  

  <noscript>
    <div class="noscript-warning">博客在允许 JavaScript 运行的环境下浏览效果更佳</div>
  </noscript>
</body>
</html>
